﻿using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;

namespace XFABManager
{
    public class ExtractResRequest : CustomAsyncOperation<ExtractResRequest>
    {

        private const int extract_res_count = 30;  // 同时释放资源的数量

        private Queue<BundleInfo> all_need_extract = new Queue<BundleInfo>();  // 所有需要释放的文件
        private List<CopyFileRequest> copy_files = new List<CopyFileRequest>();

        private List<BundleInfo> extractedFiles = new List<BundleInfo>(); // 已经释放完成的文件

        public string CurrentExtractFile { get; private set; }


        private int all_count;

        internal IEnumerator ExtractRes(string projectName) {

            CheckResUpdateRequest checkUpdate = AssetBundleManager.CheckResUpdate(projectName);
            yield return checkUpdate;

            if ( !string.IsNullOrEmpty(checkUpdate.error) ) {
                Completed(checkUpdate.error);
                yield break;
            }

            yield return CoroutineStarter.Start(ExtractRes(checkUpdate.result));

        }


//        internal IEnumerator ExtractRes( CheckUpdateResult result)
//        {

//            // 判断本地是否有这个模块资源 如果有了就不用释放了
//            if (/*AssetBundleManager.IsHaveResOnLocal(result.projectName) ||*/ result.updateType == UpdateType.DontNeedUpdate )
//            {
//                //Debug.LogWarningFormat("模块{0}资源已经释放了!",result.projectName);
//                Completed();
//                yield break;
//            }

//            // 判断是否有内置资源
//            IsHaveBuiltInResRequest isHaveBuiltInRes = AssetBundleManager.IsHaveBuiltInRes(result.projectName);
//            yield return isHaveBuiltInRes;
//            if (!isHaveBuiltInRes.isHave)
//            {
//                Completed(string.Format("释放资源失败!未查询到内置资源{0}!", result.projectName));
//                yield break;
//            }

//            // 释放压缩资源
//            string buildInRes = null;
//            string localRes = null;


//            switch (result.updateType)
//            {
//                case UpdateType.ExtractLocal:

//                    float time = Time.time;
//                    Debug.LogFormat("开始解压资源:{0}",Time.time);

//                    string project_build_info = XFABTools.BuildInDataPath(result.projectName, XFABConst.project_build_info);

//#if UNITY_ANDROID && !UNITY_EDITOR
//                    UnityWebRequest requestBuildInfo = UnityWebRequest.Get(project_build_info);
//                    yield return requestBuildInfo.SendWebRequest();
//                    ProjectBuildInfo buildInfo = JsonUtility.FromJson<ProjectBuildInfo>(requestBuildInfo.downloadHandler.text);
//#else
//                    ProjectBuildInfo buildInfo = JsonUtility.FromJson<ProjectBuildInfo>(File.ReadAllText(project_build_info));
//#endif

//                    ProjectBuildInfo local_build_info = XFABTools.LocalProjectBuildInfo(result.projectName);
//                    local_build_info.Copy(buildInfo);

//                    all_need_extract.Clear();

//                    foreach (var item in result.need_update_bundles)
//                    {
//                        all_need_extract.Enqueue(item);
//                    }

//                    // 清空本地资源 
//                    //AssetBundleManager.ClearProjectCache(result.projectName);

//                    for (int i = 0; i < result.need_update_bundles.Length; i++)
//                    {
//                        BundleInfo bundleInfo = result.need_update_bundles[i];

//                        buildInRes = XFABTools.BuildInDataPath(result.projectName, bundleInfo.bundleName);
//                        localRes = XFABTools.LocalResPath(result.projectName, bundleInfo.bundleName);

//                        CopyFileRequest copy_buildin_request = FileTools.Copy(buildInRes, localRes);
//                        yield return copy_buildin_request; 

//                        if (!string.IsNullOrEmpty(copy_buildin_request.error)) {
//                            Completed(copy_buildin_request.error);
//                            yield break;
//                        }

//                        // 更新本地配置
//                        local_build_info.UpdateBundleFile(bundleInfo.bundleName,bundleInfo.bundleSize,bundleInfo.md5);

//                        CurrentExtractFile = bundleInfo.bundleName;
//                        progress = (float)(i+1) / buildInfo.bundleInfos.Length;

//                        //yield return null;
//                    }
                     
//                    // 释放 files 文件列表文件 
//                    CopyFileRequest copy_build_info_request = FileTools.Copy(project_build_info, XFABTools.LocalResPath(result.projectName, XFABConst.project_build_info));
//                    yield return copy_build_info_request;
//                    if (!string.IsNullOrEmpty(copy_build_info_request.error))
//                    {
//                        Completed(copy_build_info_request.error);
//                        yield break;
//                    }

//                    Debug.LogFormat("解压资源完成:{0} 耗时:{1}", Time.time,Time.time - time);

//                    // 更新版本号( 释放资源不需要记录版本号, 如果释放版本号的可能会更新不到服务端的最新资源 )
//                    //XFABTools.SaveVersion(result.projectName, buildInfo.version);

//                    break;
//                default:
//                    Debug.LogErrorFormat("释放资源出错,未知类型{0}", result.updateType);
//                    break;
//            }
//            Debug.Log("资源释放结束!");
//            Completed();
//        }


        internal IEnumerator ExtractRes(CheckUpdateResult result)
        {

            // 判断本地是否有这个模块资源 如果有了就不用释放了
            if (/*AssetBundleManager.IsHaveResOnLocal(result.projectName) ||*/ result.updateType == UpdateType.DontNeedUpdate)
            {
                //Debug.LogWarningFormat("模块{0}资源已经释放了!",result.projectName);
                Completed();
                yield break;
            }

            // 判断是否有内置资源
            IsHaveBuiltInResRequest isHaveBuiltInRes = AssetBundleManager.IsHaveBuiltInRes(result.projectName);
            yield return isHaveBuiltInRes;
            if (!isHaveBuiltInRes.isHave)
            {
                Completed(string.Format("释放资源失败!未查询到内置资源{0}!", result.projectName));
                yield break;
            }

            // 释放压缩资源
            string buildInRes = null;
            string localRes = null;


            switch (result.updateType)
            {
                case UpdateType.ExtractLocal:

                    //float time = Time.time;
                    //Debug.LogFormat("开始解压资源:{0}", Time.time);

                    string project_build_info = XFABTools.BuildInDataPath(result.projectName, XFABConst.project_build_info);

#if UNITY_ANDROID && !UNITY_EDITOR
                    UnityWebRequest requestBuildInfo = UnityWebRequest.Get(project_build_info);
                    yield return requestBuildInfo.SendWebRequest();
                    ProjectBuildInfo buildInfo = JsonUtility.FromJson<ProjectBuildInfo>(requestBuildInfo.downloadHandler.text);
#else
                    ProjectBuildInfo buildInfo = JsonUtility.FromJson<ProjectBuildInfo>(File.ReadAllText(project_build_info));
#endif

                    ProjectBuildInfo local_build_info = XFABTools.LocalProjectBuildInfo(result.projectName);
                    local_build_info.Copy(buildInfo);

                    all_need_extract.Clear();

                    foreach (var item in result.need_update_bundles)
                    {
                        all_need_extract.Enqueue(item);
                    }

                    all_count = all_need_extract.Count;

                    while (all_need_extract.Count > 0 || IsCoping())
                    {
                        yield return null;

                        while (IsCanExtral()) {
                            BundleInfo bundleInfo = all_need_extract.Dequeue();

                            buildInRes = XFABTools.BuildInDataPath(result.projectName, bundleInfo.bundleName);
                            localRes = XFABTools.LocalResPath(result.projectName, bundleInfo.bundleName);
                            
                            CopyFileRequest copy_buildin_request = FileTools.Copy(buildInRes, localRes);

                            copy_buildin_request.completed += (request) =>
                            {
                                if (string.IsNullOrEmpty(request.error))
                                {
                                    // 文件释放完成
                                    extractedFiles.Add(bundleInfo);
                                    copy_files.Remove(request);
                                    // 更新本地配置 
                                    local_build_info.UpdateBundleFile(bundleInfo.bundleName, bundleInfo.bundleSize, bundleInfo.md5);
                                }
                            };

                            copy_files.Add(copy_buildin_request);
                        }
                        progress = (float)(extractedFiles.Count ) / all_count;

                        if (IsExtralAllError()) // 如果正在下载中的文件全都下载出错了 跳出循环
                            break;
                    }

                    // 检测文件是否下载出错
                    if (IsExtralError())
                    {
                        Completed(ExtralErrorMessage());
                        yield break;
                    }

                    // 释放 files 文件列表文件 
                    CopyFileRequest copy_build_info_request = FileTools.Copy(project_build_info, XFABTools.LocalResPath(result.projectName, XFABConst.project_build_info));
                    yield return copy_build_info_request;
                    if (!string.IsNullOrEmpty(copy_build_info_request.error))
                    {
                        Completed(copy_build_info_request.error);
                        yield break;
                    }

                    //Debug.LogFormat("解压资源完成:{0} 耗时:{1}", Time.time, Time.time - time);

                    // 更新版本号( 释放资源不需要记录版本号, 如果释放版本号的可能会更新不到服务端的最新资源 )
                    //XFABTools.SaveVersion(result.projectName, buildInfo.version);

                    break;
                default:
                    Debug.LogErrorFormat("释放资源出错,未知类型{0}", result.updateType);
                    break;
            }
            //Debug.Log("资源释放结束!");
            Completed();
        }


        // 判断是不是正在复制中
        private bool IsCoping()
        {
            if (copy_files.Count == 0) return false;
            foreach (var item in copy_files)
                if (!item.isDone) return true;
            return false;
        }

        // 判断是否能够释放
        private bool IsCanExtral()
        {

            if (all_need_extract.Count == 0) return false; // 没有需要下载的文件 所以不能释放

            // 判断正在释放中的文件有没有报错的
            foreach (var item in copy_files)
                if (item.isDone && !string.IsNullOrEmpty(item.error)) return false;

            // 判断数量
            if (copy_files.Count < extract_res_count) return true;

            return false;
        }

        // 判断是否释放出错
        private bool IsExtralError()
        {

            if (copy_files.Count == 0) return false;


            foreach (var item in copy_files)
                if (item.isDone && !string.IsNullOrEmpty(item.error)) return true;

            return false;
        }

        // 判断下载中的文件是不是都出错了
        private bool IsExtralAllError()
        {
            if (copy_files.Count == 0) return false;

            foreach (var item in copy_files)
                if (!item.isDone || string.IsNullOrEmpty(item.error)) return false;

            return true;
        }


        // 下载出错的信息
        private string ExtralErrorMessage()
        { 
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append("释放资源出错:").Append("\n");
            foreach (var item in copy_files)
                if (item.isDone && !string.IsNullOrEmpty(item.error))
                    stringBuilder.Append(item.error).Append("\n");

            return stringBuilder.ToString();
        }

    }

}

